home *** CD-ROM | disk | FTP | other *** search
- /*
- * ARP: Address Resolution Protocol Implementation
- *
- * adapted for ATARI + RIEBL Card plus
- *
- * FoRTec/hw/pm
- *
- * This package implements a very simple version of the Plummer Address
- * Resolution Protocol (RFC 826). It allows clients to resolve Internet
- * addresses into Ethernet addresses, and knows how to respond to an
- * address resolution request (when the transmit buffer is free).
- *
- * Routines:
- *
- * arp_handler( pkt ) => 1, if ARP packet and processed,
- * 0, if no packet there otherwise
- * < 0, if network error
- * arp_in2haddr(inaddr,haddr) => 1 if did it,
- * 0 if couldn't.
- *
- * arp_init() => < 0, if network error
- * >=0, if ok
- * arp_exit() => < 0, if network error
- * >=0, if ok
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include "pktdrv.h"
- #include "ip.h"
- #include "arp.h"
-
- #include "nettrace.h"
-
- #define noDEBUG
-
- static INADDR arp_reply; /* replied internet address */
- static arp_cache arp_tab[ARPCACHESIZE] = {0}; /* init to zero */
- #define ARP_ADDIDX 0 /* use last entry for immediate replies */
- #define ARP_GATEWAY 1 /* gateway entry */
- #define ARP_BASE 2
-
- int arp_rcv(int,char *);
- static int arp_idx = ARP_ADDIDX+ARP_BASE;
- static int arp_handle = ENOTINST;
- static volatile ARP_PACKET *arp_pkt = NULL;
- long arp_counts[2] = {0L,0L};
-
- int arp_init()
- {
- int i;
-
- for(i=0; i< ARPCACHESIZE; i++)
- arp_tab[i].inaddr = 0L;
- arp_handle = net_open(ET_ARP,arp_rcv);
- #ifdef DEBUG
- printf("arp_init\n");
- #endif
-
- if(arp_handle < 0) return(arp_handle);
-
- if(!net_demux(TRUE,arp_handler))
- {
- net_release(arp_handle);
- arp_pkt = NULL;
- return(ENOTINST);
- }
- return(arp_handle);
- }
-
- int arp_exit()
- {
- int i;
- #ifdef DEBUG
- printf("arp_exit\n");
- #endif
- if(arp_handle < 0) return(FALSE);
- i = net_release(ET_ARP);
- #ifdef DEBUG
- printf("net_release = %d\n",i);
- #endif
- net_demux(FALSE,arp_handler); /* remove from demux tab */
- #ifdef DEBUG
- printf("arp_exit\n");
- #endif
- return(i>=0);
- }
-
-
- int arp_rcv(int length, char *pkt)
- {
- if(arp_pkt) return(FALSE); /* already processing a arp packet */
- arp_pkt = (ARP_PACKET *)pkt;
- return(TRUE);
- }
-
- int arp_add2tab(INADDR inaddr,HADDR haddr)
- {
- register int i;
- for(i=0; i<ARPCACHESIZE; i++)
- if(arp_tab[i].inaddr == inaddr) return (TRUE);
-
- /* add entry only if it's not already there */
- memcpy(arp_tab[ARP_ADDIDX].haddr,haddr,sizeof(HADDR));
- arp_tab[ARP_ADDIDX].inaddr = inaddr;
- return(TRUE);
- }
-
- int arp_addgw(INADDR inaddr,HADDR haddr)
- {
- memcpy(arp_tab[ARP_GATEWAY].haddr,haddr,sizeof(HADDR));
- arp_tab[ARP_GATEWAY].inaddr = inaddr;
- return(TRUE);
- }
-
-
-
- int arp_handler(void)
- {
- register ARP *ap;
- register int i;
- extern INADDR lcl_inaddr;
-
- if(!arp_pkt) return(FALSE); /* no packet received */
-
- ap = arp_head(arp_pkt);
- #ifdef DEBUG
- printf("arp got from %8lx for %8lx\n",ap->src_inaddr,ap->dst_inaddr);
- #endif
- i=0;
- if (ap->hw_type == ARP_ET && /* have ethernet hardware, */
- ap->protocol == ET_IP && /* and internet software, */
- ap->dst_inaddr == lcl_inaddr) /* for my addr. */
- {
- arp_counts[0]++;
- switch(ap->opcode)
- {
- case ARP_REQUEST: /* be a resolution req. */
- #ifdef DEBUG
- printf("arp REQUEST\n");
- #endif
- /* format response. */
-
- ap->hw_len = (u_char)sizeof(HADDR);
- ap->pr_len = (u_char)sizeof(INADDR);
-
- ap->opcode = ARP_REPLY;
- ap->dst_inaddr = ap->src_inaddr;
- ap->src_inaddr = lcl_inaddr;
-
- memcpy(ap->dst_haddr, ap->src_haddr, sizeof(HADDR));
- /* fill ethernet header */
- memcpy(arp_pkt->et.et_dest, ap->src_haddr, sizeof(HADDR));
- arp_pkt->et.et_type = ET_ARP;
- net_getadr((int)sizeof(HADDR),ap->src_haddr);
- memcpy(arp_pkt->et.et_src, ap->src_haddr, sizeof(HADDR));
- arp_counts[1]++;
- i = net_send(ARP_PKTSIZE,(char *)arp_pkt);
- #ifdef DEBUG
- printf("arp replied \n");
- #endif
- break;
- case ARP_REPLY:
- #ifdef DEBUG
- printf("arp got reply\n");
- #endif
- for(i=0; i<ARPCACHESIZE; i++)
- {
- if(arp_tab[i].inaddr == ap->src_inaddr)
- break;
- }
- if(i==ARPCACHESIZE) break; /* I'm not waiting for a arp reply */
-
- memcpy(arp_tab[i].haddr,ap->src_haddr,sizeof(HADDR));
- arp_tab[i].timeout = 0L;
- arp_tab[i].resend = 0;
- arp_reply = 0L;
- i=0;
- break;
- }
- }
- if(!net_pktfree((char *)arp_pkt))
- {
- #ifdef DEBUG
- printf("couldn't free arp packet\n");
- #endif
- }
- arp_pkt = NULL; /* drop packet */
- return (i);
- }
-
- /*
- * Do an address resolution bit.
- */
- int arp_in2haddr(INADDR inaddr,HADDR haddr)
- {
- ARP *ap;
- int i;
- extern INADDR lcl_inaddr;
- extern HADDR bcst_haddr;
- ARP_PACKET *arp_send;
-
-
- if(inaddr == lcl_inaddr)
- { /* asked for own haddr */
- net_getadr((int)sizeof(HADDR),haddr);
- return(ARP_OK);
- }
- /* do a cachelookup */
- for(i=0; i<ARPCACHESIZE; i++)
- if(arp_tab[i].inaddr == inaddr)
- { /* found in cache */
- if(arp_tab[i].timeout)
- {
- if(arp_tab[i].timeout <= clock()) break;
- return(ARP_WAIT);
- }
- memcpy(haddr, (char *)arp_tab[i].haddr, sizeof(HADDR));
- return (ARP_OK);
- }
- if(i==ARPCACHESIZE)
- {
- arp_tab[arp_idx].inaddr = inaddr;
- arp_tab[arp_idx].timeout = clock()+ARP_TIMEOUT;
- arp_tab[arp_idx].resend = 0;
- if(++arp_idx >= ARPCACHESIZE)
- arp_idx = ARP_ADDIDX+ARP_BASE; /* wrap around */
-
- }
- else
- {
- if(arp_tab[i].resend >= ARP_RETRIES)
- {
- arp_tab[i].inaddr = 0L;
- return(ARP_FAIL);
- }
- arp_tab[i].timeout = clock()+ARP_TIMEOUT;
- arp_tab[i].resend++;
- }
- arp_send = (ARP_PACKET *)net_pktalloc(ET_ARP);
- if(!arp_send)
- {
- #ifdef DEBUG
- printf("arp: no packet\n");
- #endif
- arp_tab[i].inaddr = 0L;
- return(ARP_FAIL);
- }
- arp_send->et.et_type = ET_ARP;
- memset(arp_send->et.et_dest,0xff,sizeof(HADDR));
- net_getadr((int)sizeof(HADDR),arp_send->et.et_src);
- ap = &arp_send->arp;
- ap->hw_type = ARP_ET;
- ap->protocol = ET_IP;
- ap->hw_len = (u_char)sizeof(HADDR);
- ap->pr_len = (u_char)sizeof(INADDR);
- ap->opcode = ARP_REQUEST;
- ap->src_inaddr = lcl_inaddr;
- net_getadr((int)sizeof(HADDR),ap->src_haddr);
- ap->dst_inaddr = inaddr;
- /* ...and send the packet */
- arp_counts[1]++;
- i = net_send(ARP_PKTSIZE,(char *)arp_send );
- #ifdef DEBUG
- printf("arp sent req for %lx\n",inaddr);
- #endif
- net_pktfree((char *)arp_send);
- if(i<0)
- {
- arp_tab[i].inaddr = 0L;
- return(i);
- }
- return(ARP_WAIT);
- }
-